home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / backends / nntpget.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  11KB  |  509 lines

  1. /*  $Revision: 1.8 $
  2. **  Connect to a remote site, and get news from it to offer to our local
  3. **  server.  Read list on stdin, or get it via NEWNEWS command.  Writes
  4. **  list of articles still needed to stdout.
  5. */
  6. #include "configdata.h"
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <sys/stat.h>
  11. #include <errno.h>
  12. #if    defined(DO_NEED_TIME)
  13. #include <time.h>
  14. #endif    /* defined(DO_NEED_TIME) */
  15. #include <sys/time.h>
  16. #include <sys/uio.h>
  17. #include "paths.h"
  18. #include "clibrary.h"
  19. #include "libinn.h"
  20. #include "dbz.h"
  21. #include "nntp.h"
  22. #include "macros.h"
  23.  
  24.  
  25. /*
  26. **  All information about a site we are connected to.
  27. */
  28. typedef struct _SITE {
  29.     char    *Name;
  30.     int        Rfd;
  31.     int        Wfd;
  32.     char    Buffer[BUFSIZ];
  33.     char    *bp;
  34.     int        Count;
  35. } SITE;
  36.  
  37.  
  38. /*
  39. **  Global variables.
  40. */
  41. STATIC struct iovec    SITEvec[2];
  42. STATIC char        SITEv1[] = "\r\n";
  43. STATIC char        READER[] = "mode reader";
  44. STATIC unsigned long    STATgot;
  45. STATIC unsigned long    STAToffered;
  46. STATIC unsigned long    STATsent;
  47. STATIC unsigned long    STATrejected;
  48.  
  49.  
  50.  
  51. /*
  52. **  Read a line of input, with timeout.
  53. */
  54. STATIC BOOL
  55. SITEread(sp, start)
  56.     SITE        *sp;
  57.     char        *start;
  58. {
  59.     register char    *p;
  60.     register char    *end;
  61.     struct timeval    t;
  62.     FDSET        rmask;
  63.     int            i;
  64.     char        c;
  65.  
  66.     for (p = start, end = &start[NNTP_STRLEN - 1]; ; ) {
  67.     if (sp->Count == 0) {
  68.         /* Fill the buffer. */
  69.     Again:
  70.         FD_ZERO(&rmask);
  71.         FD_SET(sp->Rfd, &rmask);
  72.         t.tv_sec = DEFAULT_TIMEOUT;
  73.         t.tv_usec = 0;
  74.         i = select(sp->Rfd + 1, &rmask, (FDSET *)NULL, (FDSET *)NULL, &t);
  75.         if (i < 0) {
  76.         if (errno == EINTR)
  77.             goto Again;
  78.         return FALSE;
  79.         }
  80.         if (i == 0
  81.          || !FD_ISSET(sp->Rfd, &rmask)
  82.          || (sp->Count = read(sp->Rfd, sp->Buffer, sizeof sp->Buffer)) < 0)
  83.         return FALSE;
  84.         if (sp->Count == 0)
  85.         return FALSE;
  86.         sp->bp = sp->Buffer;
  87.     }
  88.  
  89.     /* Process next character. */
  90.     sp->Count--;
  91.     c = *sp->bp++;
  92.     if (c == '\n')
  93.         break;
  94.     if (p < end)
  95.         *p++ = c;
  96.     }
  97.  
  98.     /* If last two characters are \r\n, kill the \r as well as the \n. */
  99.     if (p > start && p < end && p[-1] == '\r')
  100.     p--;
  101.     *p = '\0';
  102.     return TRUE;
  103. }
  104.  
  105.  
  106. /*
  107. **  Send a line to the server, adding \r\n.  Don't need to do dot-escape
  108. **  since it's only for sending DATA to local site, and the data we got from
  109. **  the remote site already is escaped.
  110. */
  111. STATIC BOOL
  112. SITEwrite(sp, p, i)
  113.     SITE        *sp;
  114.     char        *p;
  115.     int            i;
  116. {
  117.     SITEvec[0].iov_base = p;
  118.     SITEvec[0].iov_len = i;
  119.     return xwritev(sp->Wfd, SITEvec, 2) >= 0;
  120. }
  121.  
  122.  
  123. STATIC SITE *
  124. SITEconnect(host)
  125.     char    *host;
  126. {
  127.     FILE    *From;
  128.     FILE    *To;
  129.     SITE    *sp;
  130.     int        i;
  131.  
  132.     /* Connect and identify ourselves. */
  133.     if (host)
  134.     i = NNTPconnect(host, &From, &To, (char *)NULL);
  135.     else {
  136.     host = GetConfigValue(_CONF_SERVER);
  137.     i = NNTPlocalopen(&From, &To, (char *)NULL);
  138.     }
  139.     if (i < 0) {
  140.     (void)fprintf(stderr, "Can't connect to \"%s\", %s\n",
  141.         host, strerror(errno));
  142.     exit(1);
  143.     }
  144.  
  145.     if (NNTPsendpassword(host, From, To) < 0) {
  146.     (void)fprintf(stderr, "Can't authenticate with %s, %s\n",
  147.         host, strerror(errno));
  148.     /* Don't send quit; we want the remote to print a message. */
  149.     exit(1);
  150.     }
  151.  
  152.     /* Build the structure. */
  153.     sp = NEW(SITE, 1);
  154.     sp->Name = host;
  155.     sp->Rfd = fileno(From);
  156.     sp->Wfd = fileno(To);
  157.     sp->bp = sp->Buffer;
  158.     sp->Count = 0;
  159.     return sp;
  160. }
  161.  
  162.  
  163. /*
  164. **  Send "quit" to a site, and get its reply.
  165. */
  166. STATIC void
  167. SITEquit(sp)
  168.     SITE    *sp;
  169. {
  170.     char    buff[NNTP_STRLEN];
  171.  
  172.     (void)SITEwrite(sp, "quit", 4);
  173.     (void)SITEread(sp, buff);
  174. }
  175.  
  176.  
  177. STATIC BOOL
  178. HIShaveit(mesgid)
  179.     char        *mesgid;
  180. {
  181.     register char    *p;
  182.     datum        key;
  183.     datum        value;
  184.     char        buff[NNTP_STRLEN];
  185.  
  186.     (void)strcpy(buff, mesgid);
  187.     for (p = key.dptr = buff; *p; p++)
  188.     if (*p == HIS_FIELDSEP || *p == '\n')
  189.         *p = HIS_BADCHAR;
  190.     key.dsize = p - key.dptr + 1;
  191.     value = dbzfetch(key);
  192.     return value.dptr != NULL ? TRUE : FALSE;
  193. }
  194.  
  195.  
  196. STATIC NORETURN
  197. Usage(p)
  198.     char    *p;
  199. {
  200.     (void)fprintf(stderr, "Usage error:  %s\n", p);
  201.     (void)fprintf(stderr,
  202.     "Usage:  nntpget [ -d dist -n grps [-f file | -t time -u file]] host\n");
  203.     exit(1);
  204. }
  205.  
  206.  
  207. int
  208. main(ac, av)
  209.     int        ac;
  210.     char    *av[];
  211. {
  212.     char    buff[NNTP_STRLEN];
  213.     char    mesgid[NNTP_STRLEN];
  214.     char    tbuff[SMBUF];
  215.     char    temp[BUFSIZ];
  216.     STRING    Groups;
  217.     char    *distributions;
  218.     char    *Since;
  219.     int        i;
  220.     struct tm    *gt;
  221.     struct stat    Sb;
  222.     SITE    *Remote;
  223.     SITE    *Local;
  224.     FILE    *F;
  225.     BOOL    Offer;
  226.     BOOL    Error;
  227.     BOOL    Verbose;
  228.     char    *Update;
  229.     char    *p;
  230.  
  231.     /* Set defaults. */
  232.     distributions = NULL;
  233.     Groups = NULL;
  234.     Since = NULL;
  235.     Offer = FALSE;
  236.     Update = NULL;
  237.     (void)umask(NEWSUMASK);
  238.  
  239.     /* Parse JCL. */
  240.     while ((i = getopt(ac, av, "d:f:n:t:ovu:")) != EOF)
  241.     switch (i) {
  242.     default:
  243.         Usage("Bad flag");
  244.         /* NOTREACHED */
  245.     case 'd':
  246.         distributions = optarg;
  247.         break;
  248.     case 'u':
  249.         Update = optarg;
  250.         /* FALLTHROUGH */
  251.     case 'f':
  252.         if (Since)
  253.         Usage("Only one -f -t or -u flag");
  254.         if (stat(optarg, &Sb) < 0) {
  255.         (void)fprintf(stderr, "Can't stat \"%s\", %s\n",
  256.             optarg, strerror(errno));
  257.         exit(1);
  258.         }
  259.         gt = gmtime(&Sb.st_mtime);
  260.         (void)sprintf(tbuff, "%02.2d%02.2d%02.2d %02.2d%02.2d%02.2d GMT",
  261.             gt->tm_year, gt->tm_mon + 1, gt->tm_mday,
  262.             gt->tm_hour, gt->tm_min, gt->tm_sec);
  263.         Since = tbuff;
  264.         break;
  265.     case 'n':
  266.         Groups = optarg;
  267.         break;
  268.     case 'o':
  269.         /* Open the history file. */
  270.         if (dbminit(_PATH_HISTORY) < 0) {
  271.         (void)fprintf(stderr, "Can't open history, %s\n",
  272.             strerror(errno));
  273.         exit(1);
  274.         }
  275.         Offer = TRUE;
  276.         break;
  277.     case 't':
  278.         if (Since)
  279.         Usage("Only one -t or -f flag");
  280.         Since = optarg;
  281.         break;
  282.     case 'v':
  283.         Verbose = TRUE;
  284.         break;
  285.     }
  286.     ac -= optind;
  287.     av += optind;
  288.     if (ac != 1)
  289.     Usage("No host given");
  290.  
  291.     /* Set up the scatter/gather vectors used by SITEwrite. */
  292.     SITEvec[1].iov_base = SITEv1;
  293.     SITEvec[1].iov_len = STRLEN(SITEv1);
  294.  
  295.     /* Connect to the remote server. */
  296.     if ((Remote = SITEconnect(av[0])) == NULL) {
  297.     (void)fprintf(stderr, "Can't connect to \"%s\", %s\n",
  298.         av[0], strerror(errno));
  299.     exit(1);
  300.     }
  301.     if (!SITEwrite(Remote, READER, (int)STRLEN(READER))
  302.      || !SITEread(Remote, buff)) {
  303.     (void)fprintf(stderr, "Can't start reading, %s\n", strerror(errno));
  304.     exit(1);
  305.     }
  306.  
  307.     if (Since == NULL) {
  308.     F = stdin;
  309.     temp[0] = '\0';
  310.     if (distributions || Groups)
  311.         Usage("No -d or -n when reading stdin");
  312.     }
  313.     else {
  314.     /* Ask the server for a list of what's new. */
  315.     if (Groups == NULL)
  316.         Groups = "*";
  317.     if (distributions)
  318.         (void)sprintf(buff, "NEWNEWS %s %s <%s>",
  319.             Groups, Since, distributions);
  320.     else
  321.         (void)sprintf(buff, "NEWNEWS %s %s", Groups, Since);
  322.     if (!SITEwrite(Remote, buff, (int)strlen(buff))
  323.      || !SITEread(Remote, buff)) {
  324.         (void)fprintf(stderr, "Can't start list, %s\n", strerror(errno));
  325.         exit(1);
  326.     }
  327.     if (buff[0] != NNTP_CLASS_OK) {
  328.         (void)fprintf(stderr, "Protocol error from \"%s\", got \"%s\"\n",
  329.             Remote->Name, buff);
  330.         SITEquit(Remote);
  331.         exit(1);
  332.     }
  333.  
  334.     /* Create a temporary file. */
  335.     p = getenv("TMPDIR");
  336.     (void)sprintf(temp, "%s/nntpgetXXXXXX", p ? p : _PATH_TMP);
  337.     (void)mktemp(temp);
  338.     if ((F = fopen(temp, "w+")) == NULL) {
  339.         (void)fprintf(stderr, "Can't open \"%s\", %s\n",
  340.             temp, strerror(errno));
  341.         exit(1);
  342.     }
  343.  
  344.     /* Read and store the Message-ID list. */
  345.     for ( ; ; ) {
  346.         if (!SITEread(Remote, buff)) {
  347.         (void)fprintf(stderr, "Can't read from \"%s\", %s\n",
  348.             Remote->Name, strerror(errno));
  349.         (void)fclose(F);
  350.         SITEquit(Remote);
  351.         exit(1);
  352.         }
  353.         if (EQ(buff, "."))
  354.         break;
  355.         if (Offer && HIShaveit(buff))
  356.         continue;
  357.         if (fprintf(F, "%s\n", buff) == EOF || ferror(F)) {
  358.         (void)fprintf(stderr, "Can't write \"%s\", %s\n",
  359.             temp, strerror(errno));
  360.         (void)fclose(F);
  361.         SITEquit(Remote);
  362.         exit(1);
  363.         }
  364.     }
  365.     if (fflush(F) == EOF) {
  366.         (void)fprintf(stderr, "Can't flush \"%s\", %s\n",
  367.             temp, strerror(errno));
  368.         (void)fclose(F);
  369.         SITEquit(Remote);
  370.         exit(1);
  371.     }
  372.     (void)fseek(F, (OFFSET_T)0, SEEK_SET);
  373.     }
  374.  
  375.     if (Offer) {
  376.     /* Connect to the local server. */
  377.     if ((Local = SITEconnect((char *)NULL)) == NULL) {
  378.         (void)fprintf(stderr, "Can't connect to local server, %s\n", 
  379.             strerror(errno));
  380.         (void)fclose(F);
  381.         exit(1);
  382.     }
  383.     }
  384.  
  385.     /* Loop through the list of Message-ID's. */
  386.     while (fgets(mesgid, sizeof mesgid, F) != NULL) {
  387.     STATgot++;
  388.     if ((p = strchr(mesgid, '\n')) != NULL)
  389.         *p = '\0';
  390.  
  391.     if (Offer) {
  392.         /* See if the local server wants it. */
  393.         STAToffered++;
  394.         (void)sprintf(buff, "ihave %s", mesgid);
  395.         if (!SITEwrite(Local, buff, (int)strlen(buff))
  396.          || !SITEread(Local, buff)) {
  397.         (void)fprintf(stderr, "Can't offer \"%s\", %s\n.",
  398.             mesgid, strerror(errno));
  399.         break;
  400.         }
  401.         if (atoi(buff) != NNTP_SENDIT_VAL)
  402.         continue;
  403.     }
  404.  
  405.     /* Try to get the article. */
  406.     (void)sprintf(buff, "article %s", mesgid);
  407.     if (!SITEwrite(Remote, buff, (int)strlen(buff))
  408.      || !SITEread(Remote, buff)) {
  409.         (void)fprintf(stderr, "Can't get \"%s\", %s\n",
  410.             mesgid, strerror(errno));
  411.         (void)printf("%s\n", mesgid);
  412.         break;
  413.     }
  414.     if (atoi(buff) != NNTP_ARTICLE_FOLLOWS_VAL) {
  415.         if (Offer)
  416.         (void)SITEwrite(Local, ".", 1);
  417.         continue;
  418.     }
  419.  
  420.     if (Verbose)
  421.         (void)fprintf(stderr, "%s...\n", mesgid);
  422.  
  423.     /* Read each line in the article and write it. */
  424.     for (Error = FALSE; ; ) {
  425.         if (!SITEread(Remote, buff)) {
  426.         (void)fprintf(stderr, "Can't read \"%s\" from \"%s\", %s\n",
  427.             mesgid, Remote->Name, strerror(errno));
  428.         Error = TRUE;
  429.         break;
  430.         }
  431.         if (Offer) {
  432.         if (!SITEwrite(Local, buff, (int)strlen(buff))) {
  433.             (void)fprintf(stderr, "Can't send \"%s\", %s\n",
  434.                 mesgid, strerror(errno));
  435.             Error = TRUE;
  436.             break;
  437.         }
  438.         }
  439.         else
  440.         (void)printf("%s\n", buff);
  441.         if (EQ(buff, "."))
  442.         break;
  443.     }
  444.     if (Error) {
  445.         (void)printf("%s\n", mesgid);
  446.         break;
  447.     }
  448.     STATsent++;
  449.  
  450.     /* How did the local server respond? */
  451.     if (Offer) {
  452.         if (!SITEread(Local, buff)) {
  453.         (void)fprintf(stderr, "No reply after \"%s\", %s\n",
  454.             mesgid, strerror(errno));
  455.         (void)printf("%s\n", mesgid);
  456.         break;
  457.         }
  458.         i = atoi(buff);
  459.         if (i == NNTP_TOOKIT_VAL)
  460.         continue;
  461.         if (i == NNTP_RESENDIT_VAL) {
  462.         (void)printf("%s\n", mesgid);
  463.         break;
  464.         }
  465.         (void)fprintf(stderr, "%s to \"%s\"\n", buff, mesgid);
  466.         STATrejected++;
  467.     }
  468.     }
  469.  
  470.     /* Write rest of the list, close the input. */
  471.     if (!feof(F))
  472.     while (fgets(mesgid, sizeof mesgid, F) != NULL) {
  473.         if ((p = strchr(mesgid, '\n')) != NULL)
  474.         *p = '\0';
  475.         (void)printf("%s\n", mesgid);
  476.         STATgot++;
  477.     }
  478.     (void)fclose(F);
  479.  
  480.     /* Remove our temp file. */
  481.     if (temp[0] && unlink(temp) < 0)
  482.     (void)fprintf(stderr, "Can't remove \"%s\", %s\n",
  483.         temp, strerror(errno));
  484.  
  485.     /* All done. */
  486.     SITEquit(Remote);
  487.     if (Offer)
  488.     SITEquit(Local);
  489.  
  490.     /* Update timestamp file? */
  491.     if (Update) {
  492.     if ((F = fopen(Update, "w")) == NULL) {
  493.         (void)fprintf(stderr, "Can't update %s, %s\n",
  494.             Update, strerror(errno));
  495.         exit(1);
  496.     }
  497.     (void)fprintf(F, "got %ld offered %ld sent %ld rejected %ld\n",
  498.         STATgot, STAToffered, STATsent, STATrejected); 
  499.     if (ferror(F) || fclose(F) == EOF) {
  500.         (void)fprintf(stderr, "Can't update %s, %s\n",
  501.             Update, strerror(errno));
  502.         exit(1);
  503.     }
  504.     }
  505.  
  506.     exit(0);
  507.     /* NOTREACHED */
  508. }
  509.